package ncme.auto.framework.core.aspects.base;

import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.mysql.cj.util.StringUtils;
import ncme.auto.framework.core.annotation.aspect.AutoBaseProcess;
import ncme.auto.framework.core.annotation.aspect.AutoEntityProcess;
import ncme.auto.framework.core.annotation.aspect.AutoMapperProcess;
import ncme.auto.framework.core.annotation.aspect.AutoNoEntityProcess;
import ncme.auto.framework.core.annotation.aspect.AutoNoEntitySingleProcess;
import ncme.auto.framework.core.callback.AutoProcessControllerPart;
import ncme.auto.framework.core.callback.NoEntityProcessPart;
import ncme.auto.framework.core.entities.ResMsg;
import ncme.auto.framework.core.entities.aspect.AnnotationInfo;
import ncme.auto.framework.core.entities.aspect.AspectInfo;
import ncme.auto.framework.core.entities.aspect.RequestInfo;
import ncme.auto.framework.core.entities.aspect.parameter.ParamConverter;
import ncme.auto.framework.core.entities.aspect.parameter.ServiceInfo;
import ncme.auto.framework.core.enums.Order;
import ncme.auto.framework.core.exceptions.AutoException;
import ncme.auto.framework.core.exceptions.ExceptionEnum;
import ncme.auto.framework.core.logCore.service.impl.LogServiceImpl;
import ncme.auto.framework.core.services.Impl.AspectPermissionServiceImpl;
import ncme.auto.framework.core.services.Impl.base.BaseAutoMapperServiceImpl;
import ncme.auto.framework.core.services.Impl.base.BaseReflectService;
import ncme.auto.framework.core.services.Impl.mian.AutoEntityServiceImpl;
import ncme.auto.framework.core.utils.BeanUtil;
import ncme.auto.framework.core.utils.JwtUtil;
import ncme.auto.framework.core.utils.ServiceUtil;
import ncme.auto.framework.core.utils.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class BaseAutoAspect<ProcessType> {

    //事务回滚需要
    @Autowired
    protected TransactionTemplate transactionTemplate;
    //service注入需要
    @Autowired
    protected ApplicationContext applicationContext;
    //用户管理模块
    @Autowired
    protected AspectPermissionServiceImpl aspectPermissionService;
    //日志模块
    @Autowired
    protected LogServiceImpl logService;

    //##############################################切面自定义内容##################################################

    /**
     * 参数信息预处理
     *
     * @param aspectInfo 切面信息
     */
    protected abstract void parameterPreHandler(AspectInfo aspectInfo);

    /**
     * 参数验证
     *
     * @param aspectInfo 切面信息
     */
    protected abstract void parameterVerify(AspectInfo aspectInfo);

    /**
     * 自动处理部分，仅用于AutoEntity和AutoMapper
     *
     * @param aspectInfo 切面信息
     * @return 返回结果
     */
    protected abstract ResMsg autoProcess(AspectInfo aspectInfo);

    //##############################################切面方法##################################################

    /**
     * 切面方法
     *
     * @param pjp 切点
     * @return 返回结果
     * @throws Throwable 切面异常
     */
    @Around("aspectCut()")
    protected Object around(ProceedingJoinPoint pjp) throws Throwable {
        Class<?> annotationClass = BeanUtil.getBeanGenericClassOfIndex(this.getClass(), 0);
        //日志部分起点
        Object result;
        AspectInfo aspectInfo = new AspectInfo();
        try {
            //初始化切面注解值
            initialAspectInfo(annotationClass, pjp, aspectInfo);
            //权限验证
            permissionVerify(aspectInfo);
            //获取参数信息
            parameterPreHandler(aspectInfo);
            //参数验证
            parameterVerify(aspectInfo);
            //业务处理
            if (annotationClass.equals(AutoBaseProcess.class)) {
                result = pjp.proceed();
            } else {
                result = businessProcess(aspectInfo);
            }
            //输出过滤及转换，仅在NoEntity下使用
            AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
            if ((annotationClass.equals(AutoNoEntityProcess.class) && annotationInfo.getAutoNoEntityProcess().OPEN_RESULT_FILTER())
                    || annotationClass.equals(AutoNoEntitySingleProcess.class) && annotationInfo.getAutoNoEntitySingleProcess().OPEN_RESULT_FILTER()
                    || annotationClass.equals(AutoEntityProcess.class) && !annotationInfo.getAutoEntityProcess().AUTO_EXECUTE() && annotationInfo.getAutoEntityProcess().OPEN_RESULT_FILTER()
                    || annotationClass.equals(AutoMapperProcess.class) && !annotationInfo.getAutoMapperProcess().AUTO_EXECUTE() && annotationInfo.getAutoMapperProcess().OPEN_RESULT_FILTER()) {
                result = resultHandler(result, aspectInfo);
            }
            //日志处理
            logService.saveLog(pjp, aspectInfo, result);
            return result;
        } catch (Exception e) {
            throw exceptionAndLogProcess(pjp, aspectInfo, e);
        }
    }

    //##############################################切面流程##################################################

    /**
     * 切面信息初始化
     *
     * @param annotationClass 要初始化的切面类型
     * @param pjp             切点
     * @param aspectInfo      切面信息容器
     */
    protected void initialAspectInfo(Class<?> annotationClass, ProceedingJoinPoint pjp, AspectInfo aspectInfo) {
        try {
            aspectInfo.setParameter1((Map<String, Object>) pjp.getArgs()[0]);
            RequestInfo requestInfo = aspectInfo.getRequestInfo();
            AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
            //获取请求信息
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            requestInfo.setRequest(request);
            requestInfo.setRequestTime(System.currentTimeMillis());
            requestInfo.setRequestType(requestInfo.getRequest().getMethod());
            getUserInfo(request);
            //获取注解信息
            if (annotationClass.equals(AutoEntityProcess.class)) {
                AutoEntityProcess autoEntityAnnotation = getAnnotation(pjp, AutoEntityProcess.class);
                annotationInfo.setAutoEntityProcess(autoEntityAnnotation);
                annotationInfo.setASPECT_TYPE(autoEntityAnnotation);
                annotationInfo.setLOG_MSG(autoEntityAnnotation.LOG_MSG());
                annotationInfo.setREQUEST_TYPE_CODE(autoEntityAnnotation.REQUEST_TYPE_CODE());
                annotationInfo.setPERMISSION_CODE(autoEntityAnnotation.PERMISSION_CODE());
                annotationInfo.setOPEN_RESULT_FILTER(autoEntityAnnotation.OPEN_RESULT_FILTER());
                annotationInfo.setRETURN_FIELDS(autoEntityAnnotation.RETURN_FIELDS());
                annotationInfo.setHIDDEN_FIELDS(autoEntityAnnotation.HIDDEN_FIELDS());
                //注入service impl
                aspectInfo.setBaseAutoService((AutoEntityServiceImpl<?>) getServiceImpl(annotationInfo.getAutoEntityProcess().BUSINESS_ENTITY()));
            } else if (annotationClass.equals(AutoMapperProcess.class)) {
                AutoMapperProcess autoMapperAnnotation = getAnnotation(pjp, AutoMapperProcess.class);
                annotationInfo.setAutoMapperProcess(autoMapperAnnotation);
                annotationInfo.setASPECT_TYPE(autoMapperAnnotation);
                annotationInfo.setLOG_MSG(autoMapperAnnotation.LOG_MSG());
                annotationInfo.setREQUEST_TYPE_CODE(autoMapperAnnotation.REQUEST_TYPE_CODE());
                annotationInfo.setPERMISSION_CODE(autoMapperAnnotation.PERMISSION_CODE());
                annotationInfo.setOPEN_RESULT_FILTER(autoMapperAnnotation.OPEN_RESULT_FILTER());
                annotationInfo.setRETURN_FIELDS(autoMapperAnnotation.RETURN_FIELDS());
                annotationInfo.setHIDDEN_FIELDS(autoMapperAnnotation.HIDDEN_FIELDS());
                //注入service impl
                aspectInfo.setBaseAutoService((BaseAutoMapperServiceImpl<?, ?, ?>) getServiceImpl(annotationInfo.getAutoMapperProcess().MAPPER_ENTITY()));
            } else if (annotationClass.equals(AutoNoEntityProcess.class)) {
                AutoNoEntityProcess autoNoEntityProcess = getAnnotation(pjp, AutoNoEntityProcess.class);
                annotationInfo.setAutoNoEntityProcess(autoNoEntityProcess);
                annotationInfo.setASPECT_TYPE(autoNoEntityProcess);
                annotationInfo.setLOG_MSG(autoNoEntityProcess.LOG_MSG());
                annotationInfo.setREQUEST_TYPE_CODE(autoNoEntityProcess.REQUEST_TYPE_CODE());
                annotationInfo.setPERMISSION_CODE(autoNoEntityProcess.PERMISSION_CODE());
                annotationInfo.setOPEN_RESULT_FILTER(autoNoEntityProcess.OPEN_RESULT_FILTER());
                annotationInfo.setRETURN_FIELDS(autoNoEntityProcess.RETURN_FIELDS());
                annotationInfo.setHIDDEN_FIELDS(autoNoEntityProcess.HIDDEN_FIELDS());
                //获取请求地址，用于寻找服务类的对应方法名
                RequestMapping requestMapping = getAnnotation(pjp, RequestMapping.class);
                if (requestMapping == null) throw new AutoException("controller缺少@RequestMapping注解");
                String[] paths = requestMapping.value();
                if (paths.length != 1) throw new AutoException(ExceptionEnum.ANNOTATION, "RequestMapping 注解未赋值");
                else if (paths[0].lastIndexOf("/") != 0)
                    throw new AutoException(ExceptionEnum.ANNOTATION, "RequestMapping 注解赋值异常");
                annotationInfo.setREQUEST_PATH(paths[0].substring(1));
            } else if (annotationClass.equals(AutoNoEntitySingleProcess.class)) {
                AutoNoEntitySingleProcess autoNoEntitySingleProcess = getAnnotation(pjp, AutoNoEntitySingleProcess.class);
                annotationInfo.setAutoNoEntitySingleProcess(autoNoEntitySingleProcess);
                annotationInfo.setASPECT_TYPE(autoNoEntitySingleProcess);
                annotationInfo.setLOG_MSG(autoNoEntitySingleProcess.LOG_MSG());
                String requestTypeCode = autoNoEntitySingleProcess.REQUEST_TYPE_CODE();
                if (requestTypeCode.length() != 1) throw new AutoException(ExceptionEnum.ANNOTATION, "开放请求类型应有且只有1个");
                annotationInfo.setREQUEST_TYPE_CODE(requestTypeCode);
                annotationInfo.setPERMISSION_CODE(autoNoEntitySingleProcess.PERMISSION_CODE());
                annotationInfo.setOPEN_RESULT_FILTER(autoNoEntitySingleProcess.OPEN_RESULT_FILTER());
                annotationInfo.setRETURN_FIELDS(autoNoEntitySingleProcess.RETURN_FIELDS());
                annotationInfo.setHIDDEN_FIELDS(autoNoEntitySingleProcess.HIDDEN_FIELDS());
                //获取请求地址，用于寻找服务类的对应方法名
                RequestMapping requestMapping = getAnnotation(pjp, RequestMapping.class);
                if (requestMapping == null) throw new AutoException("controller缺少@RequestMapping注解");
                String[] paths = requestMapping.value();
                if (paths.length != 1) throw new AutoException(ExceptionEnum.ANNOTATION, "RequestMapping 注解未赋值");
                else if (paths[0].lastIndexOf("/") != 0)
                    throw new AutoException(ExceptionEnum.ANNOTATION, "RequestMapping 注解赋值异常");
                annotationInfo.setREQUEST_PATH(paths[0].substring(1));
            } else if (annotationClass.equals(AutoBaseProcess.class)) {
                AutoBaseProcess autoBaseProcess = getAnnotation(pjp, AutoBaseProcess.class);
                annotationInfo.setAutoBaseProcess(autoBaseProcess);
                annotationInfo.setASPECT_TYPE(autoBaseProcess);
                annotationInfo.setLOG_MSG(autoBaseProcess.LOG_MSG());
                annotationInfo.setREQUEST_TYPE_CODE(autoBaseProcess.REQUEST_TYPE_CODE());
                annotationInfo.setPERMISSION_CODE(autoBaseProcess.PERMISSION_CODE());
            } else throw new AutoException(ExceptionEnum.NOT_EXIST, "未知切面注解");
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "切面初始化失败", e);
        }

    }

    /**
     * 接口权限验证
     *
     * @param aspectInfo 切面信息对象
     */
    protected void permissionVerify(AspectInfo aspectInfo) {
        try {
            RequestInfo requestInfo = aspectInfo.getRequestInfo();
            AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
            int requestTypeCode;
            switch (requestInfo.getRequestType()) {
                case "GET":
                    requestTypeCode = 5;
                    if (!annotationInfo.getREQUEST_TYPE_CODE().contains("5"))
                        throw new AutoException(ExceptionEnum.PERMISSION, "未开放GET权限");
                    break;
                case "POST":
                    requestTypeCode = 2;
                    if (!annotationInfo.getREQUEST_TYPE_CODE().contains("2"))
                        throw new AutoException(ExceptionEnum.PERMISSION, "未开放POST权限");
                    break;
                case "PUT":
                    requestTypeCode = 3;
                    if (!annotationInfo.getREQUEST_TYPE_CODE().contains("3"))
                        throw new AutoException(ExceptionEnum.PERMISSION, "未开放PUT权限");
                    break;
                case "DELETE":
                    requestTypeCode = 4;
                    if (!annotationInfo.getREQUEST_TYPE_CODE().contains("4"))
                        throw new AutoException(ExceptionEnum.PERMISSION, "未开放DEL权限");
                    break;
                default:
                    requestTypeCode = -1;
                    break;
            }
            if (annotationInfo.getPERMISSION_CODE() != -1) {
                Integer userId = JwtUtil.getIdFromToken(requestInfo.getRequest());
                List<Integer> userPerms = aspectPermissionService.getUserPerms(userId, requestTypeCode);
                if (userPerms == null || !userPerms.contains(annotationInfo.getPERMISSION_CODE()))
                    throw new AutoException(ExceptionEnum.PERMISSION);
            }
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "权限验证异常" + e);
        }
    }

    /**
     * 业务处理，仅放了事务回滚，实际业务执行在mainProcess中
     *
     * @param aspectInfo 切面信息
     * @return 返回结果
     * @throws Throwable 业务异常
     */
    protected Object businessProcess(AspectInfo aspectInfo) throws Throwable {
        //事务回滚处理
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        Object execute = transactionTemplate.execute(transactionStatus -> {
            try {
                //主要逻辑执行
                return mainProcess(aspectInfo);
            } catch (Throwable e) {
                transactionStatus.setRollbackOnly();
                return e;
            }
        });
        if (execute instanceof Throwable) throw (Throwable) execute;
        return execute;
    }

    /**
     * 自定义结果的返回结果处理
     *
     * @param processResult 自定义逻辑的返回结果
     * @param aspectInfo    切面信息
     * @return 处理后的结果
     */
    protected ResMsg resultHandler(Object processResult, AspectInfo aspectInfo) {
        if (processResult == null) return ResMsg.successRes(null);
        AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
        if (!annotationInfo.isOPEN_RESULT_FILTER()) return ResMsg.successRes(processResult);
        try {
            if (processResult instanceof ResMsg) {
                ResMsg resMsgResult = (ResMsg) processResult;
                if (resMsgResult.getData() == null) return resMsgResult;
                Map<String, Object> data = resMsgResult.getData();
                if (data.get("result") != null && annotationInfo.isOPEN_RESULT_FILTER()) {
                    Object resultObj = data.get("result");
                    return ResMsg.successRes(objectResultToMap(resultObj, annotationInfo.getRETURN_FIELDS(), annotationInfo.getHIDDEN_FIELDS()));
                } else return resMsgResult; //将结果直接返回
            } else {
                return ResMsg.successRes(objectResultToMap(processResult, annotationInfo.getRETURN_FIELDS(), annotationInfo.getHIDDEN_FIELDS()));
            }
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.SERVICE_OTHER, "结果处理异常，@resultHandler");
        }
    }

    /**
     * 异常处理和日志记录
     *
     * @param pjp        切点
     * @param aspectInfo 切面信息对象
     * @param oldE       异常
     * @return 处理后的异常
     */
    protected Throwable exceptionAndLogProcess(ProceedingJoinPoint pjp, AspectInfo aspectInfo, Throwable oldE) {
        class ExceptionHandler {
            Throwable getRealException(Throwable e) {
                if (e.getClass().equals(InvocationTargetException.class))
                    return getRealException(((InvocationTargetException) e).getTargetException());
                else return e;
            }
        }
        //异常处理
        Throwable e = new ExceptionHandler().getRealException(oldE);
        ResMsg resMsg = ResMsg.failResOneMes(e.getMessage(), e instanceof AutoException ? ((AutoException) e).getCode() : 1101);
        //日志处理
        String errorMsg = e.getMessage() == null ? "no error msg" : e.getMessage().length() > 249 ? e.getMessage().substring(0, 249) : e.getMessage();
        logService.saveLog(pjp, aspectInfo, resMsg);
        return e;
    }

    //##############################################流程部分###################################################

    /**
     * 获取请求用户信息
     *
     * @param request 请求
     */
    private void getUserInfo(HttpServletRequest request) {
        //获取userId及UserName放入attribute中
        int userId;
        String userName;
        //if (!request.getRequestURL().toString().contains("/permission/login")) {
        try {
            DecodedJWT token = JwtUtil.verify(request.getHeader("token"));
            Claim userIdC = token.getClaim("userId");
            Claim userNameC = token.getClaim("userName");
            userId = Integer.parseInt(userIdC.asString());
            userName = userNameC.asString();
        } catch (Exception e) {
            userId = -1;
            userName = "获取token失败";
        }
        request.setAttribute("userId", userId);
        request.setAttribute("userName", userName);
    }

    /**
     * 验证请求参数是否存在
     *
     * @param parameter      Map参数
     * @param requiredParams 需要的参数（英文逗号分隔的字符串）
     */
    protected void verifyParamsExist(Map<String, Object> parameter, String requiredParams) {
        if (StringUtil.isEmpty(requiredParams)) return;
        String[] fields = requiredParams.split(",").clone();
        for (String filed : fields) {
            Object o = parameter.get(filed);
            if (o == null || StringUtils.isEmptyOrWhitespaceOnly(o.toString()))
                if (!parameter.containsKey(filed))
                    throw new AutoException(ExceptionEnum.PARAM_FIELD, "参数不完整");
        }
    }

    /**
     * 实际业务流程
     *
     * @param aspectInfo 切面信息
     * @return 返回结果
     * @throws Throwable 业务异常
     */
    private Object mainProcess(AspectInfo aspectInfo) throws Throwable {
        try {
            AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
            Object aspectType = aspectInfo.getAnnotationInfo().getASPECT_TYPE();
            if (aspectType instanceof AutoEntityProcess || aspectType instanceof AutoMapperProcess) {
                //初始化返回结果
                ResMsg beforeRes, autoRes = null, afterRes;
                //Before自定义逻辑执行
                beforeRes = customProceed(aspectInfo, Order.Before);
                aspectInfo.setBeforeResult(beforeRes);
                //自动逻辑执行
                if ((aspectType instanceof AutoEntityProcess && annotationInfo.getAutoEntityProcess().AUTO_EXECUTE())
                        || (aspectType instanceof AutoMapperProcess && annotationInfo.getAutoMapperProcess().AUTO_EXECUTE())) {
                    autoRes = autoProcess(aspectInfo);
                    if ((aspectType instanceof AutoEntityProcess && annotationInfo.getAutoEntityProcess().OPEN_RESULT_FILTER())
                            || (aspectType instanceof AutoMapperProcess && annotationInfo.getAutoMapperProcess().OPEN_RESULT_FILTER()))
                        autoRes = resultHandler(autoRes, aspectInfo);
                    aspectInfo.setAutoResult(autoRes);
                }
                //After自定义逻辑执行
                afterRes = customProceed(aspectInfo, Order.After);
                //判断返回哪个逻辑的结果
                return afterRes != null ? afterRes : beforeRes != null ? beforeRes : autoRes;
            } else if (aspectType instanceof AutoNoEntityProcess || aspectType instanceof AutoNoEntitySingleProcess) {
                ServiceInfo serviceInfo = new ServiceInfo(null, new ParamConverter(aspectInfo.getParameter1()), aspectInfo.getRequestInfo().getRequest(), null, null, null);
                if (aspectType instanceof AutoNoEntityProcess) {
                    Object serviceImpl = applicationContext.getBean(annotationInfo.getAutoNoEntityProcess().SERVICE_CLASS());
                    //注入自定义逻辑
                    NoEntityProcessPart noEntityProcessPart = new NoEntityProcessPart();
                    Method processMethod = annotationInfo.getAutoNoEntityProcess().SERVICE_CLASS().getDeclaredMethod(annotationInfo.getREQUEST_PATH(), NoEntityProcessPart.class, ServiceInfo.class);
                    processMethod.invoke(serviceImpl, noEntityProcessPart, serviceInfo);
                    //执行以请求地址为名的方法
                    return noEntityProcessPart.process(serviceInfo);
                } else {
                    Object serviceImpl = applicationContext.getBean(annotationInfo.getAutoNoEntitySingleProcess().SERVICE_CLASS());
                    //执行以请求地址为名的方法
                    Method processMethod = annotationInfo.getAutoNoEntitySingleProcess().SERVICE_CLASS().getDeclaredMethod(annotationInfo.getREQUEST_PATH(), ParamConverter.class, Integer.class, String.class);
                    return processMethod.invoke(serviceImpl, serviceInfo.getParamConverter(), serviceInfo.getUserId(), serviceInfo.getUserName());
                }
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.AUTO_SERVICE_ERROR, "切面主逻辑异常 @mainProcess", e);
        }
    }

    /**
     * 自定义流程，仅用于AutoEntity和AutoMapper
     *
     * @param aspectInfo   切面信息
     * @param presentOrder 当前执行顺序
     * @return 返回结果
     * @throws Throwable 业务异常
     */
    private ResMsg customProceed(AspectInfo aspectInfo, Order presentOrder) throws Throwable {
        AutoProcessControllerPart autoProcessControllerPart = new AutoProcessControllerPart();
        ServiceInfo serviceInfo = new ServiceInfo(
                aspectInfo.getParameterInfo().getBusinessEntity(),
                new ParamConverter(aspectInfo.getParameterInfo().getSearchMap()),
                aspectInfo.getRequestInfo().getRequest(),
                presentOrder,
                aspectInfo.getBeforeResult(),
                aspectInfo.getAutoResult());
        if (presentOrder.equals(Order.Before)) {  //注入一次自定义逻辑就行
            BaseReflectService<?> baseReflectService = aspectInfo.getBaseAutoService();
            baseReflectService.customService(autoProcessControllerPart, serviceInfo);
        }
        return autoProcessControllerPart.process(serviceInfo);
    }

    //##############################################工具###################################################

    /**
     * 获取切面方法的某个注解
     *
     * @param pjp             切点
     * @param annotationClass 注解类型
     * @return 注解对象
     */
    private <T extends Annotation> T getAnnotation(ProceedingJoinPoint pjp, Class<T> annotationClass) {
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        return method.getAnnotation(annotationClass);
    }

    /**
     * 获取业务类型对应的服务实现类
     *
     * @param argClass 业务类型
     * @return 对应的服务实现类
     */
    private Object getServiceImpl(Class<?> argClass) {
        String entityPath = argClass.getName();
        String simpleName = argClass.getSimpleName();
        String servicePath = entityPath.replace("entity", "service.impl")
                .replace(simpleName, simpleName + "ServiceImpl");
        try {
            return applicationContext.getBean(Class.forName(servicePath));
        } catch (ClassNotFoundException e) {
            throw new AutoException(ExceptionEnum.NOT_EXIST, servicePath + "不存在，请检查目录结构和命名规则");
        }

    }

    /**
     * 对象中的bean转为Map，如果是业务对象，则转为Map，如果是List<业务对象>，则转为List<Map>
     *
     * @param result       返回结果
     * @param retainFields 需要返回的字段（英文逗号分隔的字符串）
     * @param dropFields   需要提出的字段名（英文逗号分隔的字符串）
     * @return
     */
    private Object objectResultToMap(Object result, String retainFields, String dropFields) {
        if (result instanceof Map) {
            Map<String, Object> resultMap = (Map<String, Object>) result;
            List<String> excludeFields = getExcludeFields(result, retainFields, dropFields);
            excludeFields.forEach(resultMap::remove);
            return resultMap;
        } else if (result instanceof ArrayList) {  //list类型
            ArrayList<?> resultList = (ArrayList<?>) result;
            if (resultList.size() == 0) return new ArrayList<>();
            List<String> excludeFields = getExcludeFields(resultList.get(0), retainFields, dropFields);
            return BeanUtil.beansToMaps(resultList, excludeFields, false);
        } else {                            //object类型
            List<String> excludeFields = getExcludeFields(result, retainFields, dropFields);
            return BeanUtil.beanToMap(result, excludeFields, false);
        }
    }

    /**
     * 获取排除的字段名
     *
     * @param bean         实体类型
     * @param retainFields 需要返回的字段
     * @param dropFields   需要丢弃的字段（仅在retainFields为空时启用）
     * @return 需要排除的字段名
     */
    private List<String> getExcludeFields(Object bean, String retainFields, String dropFields) {
        if (bean == null) return new ArrayList<>();
        if (!StringUtils.isNullOrEmpty(retainFields)) {
            List<String> allFields = new ArrayList<>();
            if (bean instanceof HashMap)
                allFields.addAll(BeanUtil.mapBeanToMap(bean).keySet());
            else Arrays.asList(bean.getClass().getDeclaredFields()).forEach(field -> allFields.add(field.getName()));
            List<String> includes = new ArrayList<>(org.springframework.util.StringUtils.commaDelimitedListToSet(retainFields));
            return ServiceUtil.listSubtraction(allFields, includes);
        } else {
            ArrayList<String> strings = new ArrayList<>(org.springframework.util.StringUtils.commaDelimitedListToSet(dropFields));
            strings.add("isDeleted");
            strings.add("version");
            return strings;
        }
    }

}
